using System;
using System.Linq;

namespace MvpFramework.Infastructure
{
    /// <summary>
    /// Resolvers Views that use <see cref="Presenter{T}"/>
    /// </summary>
    public class GenericTypeResolver : IViewPresenterResolver
    {
        /// <summary>
        /// Returns the Presenter for the view
        /// </summary>
        /// <param name="view"></param>
        /// <returns></returns>
        public Type GetPresenterTypeFor(object view)
        {
            var viewType = GetViewTypeFor(view);
            var baseType = FindBasePresenterFor(viewType);
            foreach (var type in viewType.Assembly.GetTypes())
            {
                if (IsABasePresenter(type, baseType))
                {
                    return type;
                }
            }
            throw new InvalidOperationException(
                String.Format("Can not find a class inheriting Presenter<{0}> in Assembly", viewType.Name));
        }
        /// <summary>
        /// Returns the View for the page
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        public Type GetViewTypeFor(object page)
        {
            var pageType = page.GetType();
            foreach (var type in pageType.GetInterfaces())
            {
                var viewType = GetViewFromInterface(type);
                if (viewType != null)
                {
                    return viewType;
                }
            }
            throw new InvalidOperationException("View must implement IMvpView in order to use GenericTypeResolver");
        }
        private static Type GetViewFromInterface(Type @interface)
        {
            if (!@interface.IsInterface)
            {
                return null;
            }
            if(InheritsIMvpView(@interface))
            {
                return @interface; 
            }
            return null;
        }

        private static bool InheritsIMvpView(Type @interface)
        {
            return @interface.GetInterfaces().FirstOrDefault(i => i == typeof (IMvpView)) != null;
        }

        private static bool IsABasePresenter(Type type, object baseType)
        {
            return type.BaseType != null && type.BaseType == baseType;
        }

        private static object FindBasePresenterFor(Type type)
        {
            var presenterType = typeof(Presenter<>);
            var view = new[] { type };
            return presenterType.MakeGenericType(view);

        }



    }
}